"""
pspy.gae.web is a collection of classes that are
used to manage the web request / response 
processing by wrapping various native 
gae objects.
"""
from pspy import Notification

SESSION_KEY = "PSPYDER_SESSION_KEY"

# timings
MINUTES = MINUTE = 60
HOUR = HOURS = 60 * MINUTES
DAY = DAYS = 24 * HOURS
YEAR = YEARS = 365 * DAY
DEFAULT_TIMEOUT = 30 * MINUTES
MAX_TIMEOUT = DAY

class Response:
    "used as a dynamic container"
    pass

class Request(object):
    "Wraps a twisted.web.Request to enhance data collection"
    def __init__(self, webReq, session=None, domain=None):
        # save attributes
        self._domain = domain 
        self._webReq = webReq
        self._sess = session
        self._attrs = {}
        self._respHeaders = { }
        self._respPg = None
        self._outputFormat = 'xhtml-strict'
        self._chainTo = None
        self.host = webReq.host
        self.path = webReq.path
        self.url = webReq.url

        # set platform flags
        uAgent = self.getHeader('USER_AGENT').lower()
        self._platform = {"mobile":0,"ipad":0,"android":0,"iphone":0, "tablet":0, 'mobileos':0 }
        
        # are we mobile?
        if uAgent.find('mobile') >= 0:
            self._platform['mobileos'] = True
            # check for iPhone
            self._platform["mobile"] = True
            if uAgent.find("iphone") >= 0:
                self._platform['iphone'] = True
        
        # check for ipad
        if uAgent.find("ipad") >= 0:
            self._platform['ipad'] = True
            self._platform['tablet'] = True
        
        # advanced devices :) 
        if uAgent.find("android") >= 0:
            self._platform['mobileos'] = True
            self._platform['android'] = True
            
            # what class of android
            self._platform['tablet'] = not self._platform['mobile']

    #------------------------------
    # wrapper functions for the
    # GAE request object
    #------------------------------
    
    #--------------------------------------
    # HTTP Headers
    #--------------------------------------

    def getHeader(self, nam):
        return self._webReq.headers[nam]
    
    def getHeaders(self):      
        return self._webReq.headers
    
    def getHost(self):
        return self.host()

    # platform queries
    def _isMobile(self):
        return self._platform['mobile']
    isMobile = property(_isMobile)
    
    def _isMobileOS(self):
        return self._platform['mobileos']    
    isMobileOS = property(_isMobileOS)
    
    def _isIPad(self):
        return self._platform['ipad']
    isIPad = property(_isIPad)
    
    def _isIPhone(self):
        return self._platform['iphone']
    isMobileOS = property(_isIPhone)

    def _isAndroid(self):
        return self._platform['android']
    isAndroid = property(_isAndroid)

    def _isTablet(self):
        return self._platform['Tablet']
    isTablet = property(_isTablet)

    #--------------------------------------
    # post data and get QS parameters
    #--------------------------------------
    def getDefParameterMap(self):
        "return form elements as map"
        rv = {}
        for nm in self._webReq.arguments():
            rv[nm] = self._webReq.get(nm)
            
        return rv
    
    def getParameters(self, flatten=True):
        rv = {}
        for nm in self._webReq.arguments():
            rv[nm] = self._webReq.get_all(nm)
            if flatten:
                rv[nm] = rv[nm][0]
                
        return rv
    
    def getParameter(self, name, val=None):
        "get form element value"
        return self._webReq.get(name,default_value=val)
    
    def hasParameter(self, name):
        "check for web form element existance"
        return name in self._webReq.arguments()
    
    def getParameterNames(self):
        "return list of form element names"
        return self._webReq.arguments()
    
    def getFileData(self,parm,location=None):
        '''
        Returns raw data from file uploaded
        via multi-part web form.  If location
        is given and points to a valid file
        location, the data will be written 
        to file from the stream and the 
        file info return instead.
        '''
        f = None
        try:
            # do this first and bail if fails
            if location:
                f = open(location,"w+")
                # save it all
                sz = f.write(self.getParameters()[parm])
                f.close()
            
                # location not content
                rtn = location
            else:
                rtn = self.getParameters()[parm]
                sz = len(rtn)
        
        except Exception, ex:
            return str(ex), -1
                    
        # done
        return rtn, sz

    #--------------------------------
    #  Cookie management        
    #--------------------------------
    
    def getCookie(self, cname):
        rv = None

        if self._webReq.cookies.has_key[cname]:
            rv = self._webReq.cookies[cname]
 
        return rv

    def addCookie(self, cname, cval):
        self._webReq.cookies[cname] = cval
    
    #--------------------------------
    #  Session property is a dict        
    #--------------------------------
    def getSession(self,create=False):
        "return the user session"                
        return self._sess
    def setSession(self,sess):
        self._sess = sess        
    session = property(getSession,setSession)
    
    #--------------------------------
    #  Request attributes management        
    #--------------------------------
    
    def getAttributes(self):
        "get the list of process attributes"
        return self._attrs
    
    def getAttribute(self, name, default=None):
        "retrieve the value of an attribute"
        rv = default
        if self.hasAttribute(name):
            rv = self._attrs[name]
        return rv
 
    def setAttribute(self, name, value):
        "set a process attribute value"
        self._attrs[name] = value
        
    def hasAttribute(self, name):
        "check for existance of a process attribute"
        return self._attrs.has_key(name)
    
    def getAttributeNames(self):
        "return list of process attribute names"
        return self._attrs.keys()
    
    #------------------------------
    # Pspy request functionality
    #------------------------------

    def chainToAction(self, actionName):
        self._chainTo = actionName
    
    def getOutputFormat(self):
        "get the template formatting type"
        return self._outputFormat
    
    def setOutputFormat(self, fmt):
        "set the template formatting type"
        self._outputFormat = fmt

    def getResponsePage(self):
        "get the current result page"
        return self._respPg
    
    def setResponsePage(self, page):
        "set the name of the response template"
        self._respPg = page
        
    def getResponse(self, direct=False, presets={}):
        "return the gathered data and output formatting options"
        # start witn presets
        data = presets.copy()

        # session first
        # data.update(self._domain.getSession(self._sessid).getAttributes())
            
        # web args in lists
        for k in self._webReq.arguments():
            data[k] = self._webReq.get(k)
        
        # add in the process attributes
        data.update(self._attrs)
        
        # build response object
        resp = Response()
        
        if data.has_key('results') and not data.has_key('resultCode'):
            try:
                p = data['results'].split("::")
                data['resultCode'] = p[0]
                data['resultMessage'] = p[1]
            except Exception as ex:
                Notification("-- Results Field Error: %s" % str(ex)).setException(ex)
                data['resultCode'] = 0
                data['resultMessage'] = ''
                
        # set chain node 
        resp.nextAction = self._chainTo
        
        # check for chaining
        if self._chainTo:
            # pass the torch
            resp.request = self
        
        else:    
            # transfer the data
            resp.data = data
            resp.outputFormat = self._outputFormat
            
            if direct:
                resp.responsePage = None
            else:
                resp.responsePage = self._respPg

        # return to sender
        return resp
    
    def setRespHeader(self,name,val):
        "add raw resp header"
        self._domain.response.headers[name] = val
        
    def getRespHeaders(self,name=None):
        "get one or all headers"
        try:
            return self._domain.headers[name]
        except:
            return None
    
